package com.mlnx.bptp;

import com.mlnx.bptp.body.Body;
import com.mlnx.bptp.body.PacketType;
import com.mlnx.bptp.exception.InvalidPacketException;
import com.mlnx.bptp.head.Header;
import com.mlnx.bptp.util.DecodeCRC16;

import java.nio.ByteBuffer;
import java.text.ParseException;

/**
 * @author zzb
 * @create 2019/3/25 12:26
 */
public class BpPacket implements Codec {
    private static final ByteBuffer buffer = ByteBuffer
            .allocate(10000);
    public static final byte[] Heads = { (byte) 0xFA}; // 数据包包头字节
    public static boolean shouldCheckSum = true;
    private Header head;
    private Body body;

    public Header getHead() {
        return head;
    }

    public void setHead(Header head) {
        this.head = head;
    }

    public Body getBody() {
        return body;
    }

    public void setBody(Body body) {
        this.body = body;
    }
    public BpPacket() {
        super();
        init();
    }

    @Override
    public void init() {
        body = new Body();
        body.init();
    }

    @Override
    public void decode(ByteBuffer buf) throws ParseException {
        if(shouldCheckSum){
            checkSum(buf);
        }
        body.decode(buf);
    }

    @Override
    public byte[] encode() {
        synchronized (BpPacket.class) {
            buffer.clear();

            byte[] bs = body.encode();
            buffer.put(bs);
            buffer.flip();
            bs = new byte[buffer.remaining()];
            buffer.get(bs);

            return bs;
        }
    }


    public void checkSum(ByteBuffer buf) {
        buf.mark();
        int lengths=buf.remaining();
        byte[] bs = new byte[lengths];
        buf.get(bs);//除头和长度外的数据
        byte[] b1={(byte)0xFa,(byte)(lengths+2)};//添加完整数据头和长度
        byte[] b2 = new byte[lengths-2];//截取除了CRC16验证码的数据
//        LogUtils.e("除去FA和长度的数据："+ TurnByte.bytesToHex(bs));
//        System.out.println("除去FA和长度的数据："+ TurnByte.bytesToHex(bs)+"数据长度："+bs.length);
        System.arraycopy(bs, 0, b2, 0, lengths-2);
        byte[] b3 = new byte[b1.length+b2.length];//将数据拼接完整
        System.arraycopy(b1, 0, b3, 0, b1.length);
        System.arraycopy(b2, 0, b3, b1.length, b2.length);
        byte[] b4=DecodeCRC16.Crc16cal1(b3);//CRC16验证
        if(!(b4[lengths]==bs[lengths-2]&&b4[lengths+1]==bs[lengths-1])){
            throw new InvalidPacketException(String.format("checksum失败 收到CRC16:0x%x,0x%x  计算checksum:0x%x,0x%x",
                    bs[lengths-2], bs[lengths-1],b4[lengths], b4[lengths+1]));
        }
        buf.reset();
    }
    /**
     * pong 服务器回复设备
     */
    public static BpPacket pong() {
        BpPacket bpPacket=new BpPacket();
//		LogUtils.i("pong");
        bpPacket.getBody().setPacketType(PacketType.PING_PACKET);
        return bpPacket;
    }


}
